#region Header Block
/*
--------------------------------------------------------------------------------------------
 Part of CalcSharp project
 CalcSharp (c) 2008 Webmaster442
--------------------------------------------------------------------------------------------
 File Name: ReversePolishNotation.cs
 Function: Reverse Polish Notation interpretation class
           Heavily modified version of the code found at: http://www.dreamincode.net/forums/showtopic35320.htm.
           Original code by:  orcasquall
--------------------------------------------------------------------------------------------
*/
#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using CalcSharp.Core;

namespace CalcSharp
{
    public enum TokenType
    {
        None,
        Number,
        Constant,
        Plus,
        Minus,
        Multiply,
        Divide,
        Exponent,
        UnaryMinus,
        LeftParenthesis,
        SquareLeftParenthesis,
        BlockLeftParenthesis,
        RightParenthesis,
        SquareRightParenthesis,
        BlockRightParenthesis,
        Mod,
        // Logic ->
        Or,
        And,
        //compare ->
        Biggerthan,
        Smallerthan,
        COR,
        CAND,
        CEQ,
        CNEQ,
        // Functions ->
        FuncToken,
        UserFunction,
        ParamSeperator,
        //vallue Store
        OpStore,
        OpStoreAdd,
        OpStoreSub,
        OpStoreMul,
        OpStoreDiv
    }

    public struct ReversePolishNotationToken
    {
        public string TokenValue;
        public TokenType TokenValueType;
        public override bool Equals(object obj)
        {
            ReversePolishNotationToken ob = (ReversePolishNotationToken)obj;
            return ob.TokenValue == this.TokenValue;
        }
        public override int GetHashCode()
        {
            return this.TokenValue.GetHashCode();
        }
        public static bool operator ==(ReversePolishNotationToken p1, ReversePolishNotationToken p2)
        {
            return p1.Equals(p2);
        }
        public static bool operator !=(ReversePolishNotationToken p1, ReversePolishNotationToken p2)
        {
            return !p1.Equals(p2);
        }
    }

    public class ReversePolishNotation
    {
        private Queue<ReversePolishNotationToken> output;
        private Stack<ReversePolishNotationToken> ops;
        private string lastvar;

        public static FunctionLoader Functions;

        static ReversePolishNotation()
        {
            ReversePolishNotation.Functions = new FunctionLoader();
        }

        private string sOriginalExpression;
        public string OriginalExpression
        {
            get { return sOriginalExpression; }
        }
        private string sTransitionExpression;
        public string TransitionExpression
        {
            get { return sTransitionExpression; }
        }

        private string sPostfixExpression;
        public string PostfixExpression
        {
            get { return sPostfixExpression; }
        }

        public ReversePolishNotation()
        {
            sOriginalExpression = string.Empty;
            sTransitionExpression = string.Empty;
            sPostfixExpression = string.Empty;
        }

        public void Parse(string Expression)
        {
            output = new Queue<ReversePolishNotationToken>();
            ops = new Stack<ReversePolishNotationToken>();

            sOriginalExpression = Expression;
            StringBuilder userfuncts = new StringBuilder();
            int counter = 0;
            userfuncts.Append("|");
            foreach (string f in Program.functionmem.keys)
            {
                userfuncts.Append(f.ToLower());
                counter++;
                if (counter < Program.functionmem.keys.Length-1) userfuncts.Append("|");
            }


            // captures numbers. Anything like 11 or 22.34 is captured, ignore variables: ^[^$]
            string sBuffer = Expression.ToLower(CultureInfo.CurrentCulture);
            sBuffer = Regex.Replace(sBuffer, @"(?<number>^[^$]([\da-fA-F])+(\,\d+)?[boh]?$)", " ${number} ");
            //sBuffer = Regex.Replace(sBuffer, @"(?<number>^[^$]\d+(\,\d+)?)", " ${number} ");
     
            // captures ==, !=, or, and, := operators
            sBuffer = Regex.Replace(sBuffer, @"(?<logops>(==|(:=)|(\+=)|(\-=)|(\*=)|(\/=)|(!=)|and|or))", " ${logops} ");
            sBuffer = sBuffer.Replace("+=", "sadd");
            sBuffer = sBuffer.Replace("-=", "suadd");
            sBuffer = sBuffer.Replace("*=", "madd");
            sBuffer = sBuffer.Replace("/=", "dadd");
            // captures these symbols: + - * / ^ ( )
            sBuffer = Regex.Replace(sBuffer, @"(?<ops>[+\-*/^\(\)\[\]\{\};\<\>\|\&\%])", " ${ops} ");
            //captures functions
            if (userfuncts.Length > 1) sBuffer = Regex.Replace(sBuffer, @"(?<alpha>(^\" +ReversePolishNotation.Functions.RegexFunctions + userfuncts.ToString() +"))", " ${alpha} ");
            else Regex.Replace(sBuffer, @"(?<alpha>(^\" + ReversePolishNotation.Functions.RegexFunctions + "))", " ${alpha} ");
            //find variables
            sBuffer = Regex.Replace(sBuffer, @"(?<mtrxs>\#[a-z1-9_-]+\[\d\;\d\])", " ${mtrxs} ");
            sBuffer = Regex.Replace(sBuffer, @"(?<sets>\@[a-z1-9_-]+\[\d\])", " ${sets} ");
            sBuffer = Regex.Replace(sBuffer, @"(?<vars>\$[a-z1-9_-]+)", " ${vars} ");
            //
            // trims up consecutive spaces and replace it with just one space
            sBuffer = Regex.Replace(sBuffer, @"\s+", " ").Trim();

            // The following chunk captures unary minus operations.
            // 1) We replace every minus sign with the string "MINUS".
            // 2) Then if we find a "MINUS" with a number or constant or a ) in front,
            //    then it's a normal minus operation.
            // 3) Otherwise, it's a unary minus operation.

            // Step 1.
            sBuffer = Regex.Replace(sBuffer, "-", "MINUS");
            // Step 2. Looking for pi or e or generic number \d+(\.\d+)?
            //^\$[a-z1-9]+
            sBuffer = Regex.Replace(sBuffer, @"(?<number1>(\$[a-z1-9_-]+|\)|(\@[a-z1-9_-]+\[\d\])|(\#[a-z1-9_-]+\[\d\;\d\])|(\d+(\.\d+)?)))\s+MINUS", "${number1} -");
            // Step 3. Use the tilde ~ as the unary minus operator
            sBuffer = Regex.Replace(sBuffer, "MINUS", "~");

            sTransitionExpression = sBuffer;

            // tokenise it!
            string[] saParsed = sBuffer.Split(" ".ToCharArray());
            int i = 0;
            double tokenvalue;
            ReversePolishNotationToken token, opstoken;
            for (i = 0; i < saParsed.Length; ++i)
            {
                token = new ReversePolishNotationToken();
                token.TokenValue = saParsed[i];
                token.TokenValueType = TokenType.None;
                try
                {
                    if (saParsed[i][0] == '$' || saParsed[i][0] == '#' || saParsed[i][0] == '@')
                    {
                        token.TokenValueType = TokenType.Constant;
                        output.Enqueue(token);
                    }
                    else
                    {
                        tokenvalue = double.Parse(saParsed[i]);//double.Parse(saParsed[i]);
                        token.TokenValueType = TokenType.Number;
                        // If the token is a number, then add it to the output queue.
                        output.Enqueue(token);
                    }
                }
                catch
                {
                    switch (saParsed[i])
                    {
                        case "+":
                            token.TokenValueType = TokenType.Plus;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "<":
                            token.TokenValueType = TokenType.Smallerthan;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case ">":
                            token.TokenValueType = TokenType.Biggerthan;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "==":
                            token.TokenValueType = TokenType.CEQ;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "!=":
                            token.TokenValueType = TokenType.CNEQ;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "and":
                            token.TokenValueType = TokenType.CAND;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "or":
                            token.TokenValueType = TokenType.COR;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "|":
                            token.TokenValueType = TokenType.Or;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "&":
                            token.TokenValueType = TokenType.And;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "-":
                            token.TokenValueType = TokenType.Minus;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "*":
                            token.TokenValueType = TokenType.Multiply;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    if (opstoken.TokenValueType == TokenType.Plus || opstoken.TokenValueType == TokenType.Minus) break;
                                    else
                                    {
                                        // Once we're in here, the following algorithm condition is satisfied.
                                        // o1 is associative or left-associative and its precedence is less than (lower precedence) or equal to that of o2, or
                                        // o1 is right-associative and its precedence is less than (lower precedence) that of o2,

                                        // pop o2 off the stack, onto the output queue;
                                        output.Enqueue(ops.Pop());
                                        if (ops.Count > 0) opstoken = ops.Peek();
                                        else break;
                                    }
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "/":
                            token.TokenValueType = TokenType.Divide;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    if (opstoken.TokenValueType == TokenType.Plus || opstoken.TokenValueType == TokenType.Minus) break;
                                    else
                                    {
                                        // Once we're in here, the following algorithm condition is satisfied.
                                        // o1 is associative or left-associative and its precedence is less than (lower precedence) or equal to that of o2, or
                                        // o1 is right-associative and its precedence is less than (lower precedence) that of o2,

                                        // pop o2 off the stack, onto the output queue;
                                        output.Enqueue(ops.Pop());
                                        if (ops.Count > 0) opstoken = ops.Peek();
                                        else break;
                                    }
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "%":
                            token.TokenValueType = TokenType.Mod;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    if (opstoken.TokenValueType == TokenType.Plus || opstoken.TokenValueType == TokenType.Minus) break;
                                    else
                                    {
                                        // Once we're in here, the following algorithm condition is satisfied.
                                        // o1 is associative or left-associative and its precedence is less than (lower precedence) or equal to that of o2, or
                                        // o1 is right-associative and its precedence is less than (lower precedence) that of o2,

                                        // pop o2 off the stack, onto the output queue;
                                        output.Enqueue(ops.Pop());
                                        if (ops.Count > 0) opstoken = ops.Peek();
                                        else break;
                                    }
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "^":
                            token.TokenValueType = TokenType.Exponent;
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "~":
                            token.TokenValueType = TokenType.UnaryMinus;
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "(":
                            token.TokenValueType = TokenType.LeftParenthesis;
                            // If the token is a left parenthesis, then push it onto the stack.
                            ops.Push(token);
                            break;
                        case "[":
                            token.TokenValueType = TokenType.SquareLeftParenthesis;
                            ops.Push(token);
                            break;
                        case "{":
                            token.TokenValueType = TokenType.BlockLeftParenthesis;
                            ops.Push(token);
                            break;
                        case ")":
                            token.TokenValueType = TokenType.RightParenthesis;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // Until the token at the top of the stack is a left parenthesis
                                while (opstoken.TokenValueType != TokenType.LeftParenthesis)
                                {
                                    // pop operators off the stack onto the output queue
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else throw new CSException("Unbalanced () parenthesis!");
                                }
                                // Pop the left parenthesis from the stack, but not onto the output queue.
                                ops.Pop();
                            }
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // If the token at the top of the stack is a function token
                                if (opstoken.TokenValueType == TokenType.FuncToken || opstoken.TokenValueType == TokenType.UserFunction) output.Enqueue(ops.Pop());
                            }
                            break;
                        case "]":
                            token.TokenValueType = TokenType.SquareRightParenthesis;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                while (opstoken.TokenValueType != TokenType.SquareLeftParenthesis)
                                {
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else throw new CSException("Unbalanced [] parenthesis!");
                                }
                                ops.Pop();
                            }
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                if (opstoken.TokenValueType == TokenType.FuncToken || opstoken.TokenValueType == TokenType.UserFunction) output.Enqueue(ops.Pop());
                            }
                            break;
                        case "}":
                            token.TokenValueType = TokenType.BlockRightParenthesis;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                while (opstoken.TokenValueType != TokenType.BlockLeftParenthesis)
                                {
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else throw new CSException("Unbalanced {} parenthesis!");
                                }
                                ops.Pop();
                            }
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                if (opstoken.TokenValueType == TokenType.FuncToken || opstoken.TokenValueType == TokenType.UserFunction) output.Enqueue(ops.Pop());
                            }
                            break;
                        case "$pi":
                        case "$e":
                            token.TokenValueType = TokenType.Constant;
                            // If the token is a number, then add it to the output queue.
                            output.Enqueue(token);
                            break;
                        case ";":
                            token.TokenValueType = TokenType.ParamSeperator;
                            ops.Push(token);
                            break;
                        case ":=":
                            token.TokenValueType = TokenType.OpStore;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "sadd":
                            token.TokenValueType = TokenType.OpStoreAdd;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "suadd":
                            token.TokenValueType = TokenType.OpStoreSub;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "madd":
                            token.TokenValueType = TokenType.OpStoreMul;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        case "dadd":
                            token.TokenValueType = TokenType.OpStoreDiv;
                            if (ops.Count > 0)
                            {
                                opstoken = ops.Peek();
                                // while there is an operator, o2, at the top of the stack
                                while (IsOperatorToken(opstoken.TokenValueType))
                                {
                                    // pop o2 off the stack, onto the output queue;
                                    output.Enqueue(ops.Pop());
                                    if (ops.Count > 0) opstoken = ops.Peek();
                                    else break;
                                }
                            }
                            // push o1 onto the operator stack.
                            ops.Push(token);
                            break;
                        default:
                            if (ReversePolishNotation.Functions[token.TokenValue] > 0 || Program.functionmem.isset(token.TokenValue))
                            {
                                if (Program.functionmem.isset(token.TokenValue))
                                {
                                    token.TokenValueType = TokenType.UserFunction;
                                    ops.Push(token);
                                }
                                else
                                {
                                    token.TokenValueType = TokenType.FuncToken;
                                    ops.Push(token);
                                }
                            }
                            else
                            {
                                if (token.TokenValue.StartsWith("$") || token.TokenValue.StartsWith("@") || token.TokenValue.StartsWith("#")) token.TokenValueType = TokenType.Constant;
                                else token.TokenValueType = TokenType.Number;
                                // If the token is a number, then add it to the output queue.
                                output.Enqueue(token);
                            }
                            break;
                    }
                }
            }

            // When there are no more tokens to read:

            // While there are still operator tokens in the stack:
            while (ops.Count != 0)
            {
                opstoken = (ReversePolishNotationToken)ops.Pop();
                // If the operator token on the top of the stack is a parenthesis
                if (opstoken.TokenValueType == TokenType.LeftParenthesis || opstoken.TokenValueType == TokenType.SquareLeftParenthesis || opstoken.TokenValueType == TokenType.BlockLeftParenthesis)
                {
                    // then there are mismatched parenthesis.
                    throw new CSException("There are unbalanced parenthesises in the expression");
                }
                else
                {
                    // Pop the operator onto the output queue.
                    output.Enqueue(opstoken);
                }
            }

            sPostfixExpression = string.Empty;
            StringBuilder postfix = new StringBuilder();
            foreach (ReversePolishNotationToken obj in output)
            {
                postfix.AppendFormat("{0} ", obj.TokenValue);
            }
            sPostfixExpression = postfix.ToString();
            postfix = null;
        }

        private double tmp;

        public double Evaluate()
        {
            Stack result = new Stack();
            double oper1 = 0.0, oper2 = 0.0;
            int reqparams;
            // While there are input tokens left
            foreach (ReversePolishNotationToken token in output)
            {
                // Read the next token from input.
                switch (token.TokenValueType)
                {
                    case TokenType.Number:
                        result.Push(MiscFuncts.parsestr(token.TokenValue));
                        break;
                    case TokenType.Constant:
                        result.Push(MiscFuncts.parsestr(token.TokenValue));
                        if (string.IsNullOrEmpty(lastvar)) lastvar = token.TokenValue;
                        break;
                    case TokenType.Plus:
                        // NOTE: n is 2 in this case
                        // If there are fewer than n values on the stack
                        if (result.Count >= 2)
                        {
                            // So, pop the top n values from the stack.
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            // Evaluate the function, with the values as arguments.
                            // Push the returned results, if any, back onto the stack.
                            result.Push(oper1 + oper2);
                        }
                        else throw new CSException("Evaluation error at: +");
                        break;
                    case TokenType.Minus:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            result.Push(oper1 - oper2);
                        }
                        else throw new CSException("Evaluation error at: -");
                        break;
                    case TokenType.Smallerthan:
                        {
                            if (result.Count >= 2)
                            {
                                oper2 = (double)result.Pop();
                                oper1 = (double)result.Pop();
                                if (oper1 < oper2) tmp = 1;
                                else tmp = 0;
                                result.Push(tmp);
                            }
                            else throw new CSException("Evaluation error at: <");
                            break;
                        }
                    case TokenType.CEQ:
                        {
                            if (result.Count >= 2)
                            {
                                oper2 = (double)result.Pop();
                                oper1 = (double)result.Pop();
                                if (oper1 == oper2) tmp = 1;
                                else tmp = 0;
                                result.Push(tmp);
                            }
                            else throw new CSException("Evaluation error at: ==");
                            break;
                        }
                    case TokenType.CNEQ:
                        {
                            if (result.Count >= 2)
                            {
                                oper2 = (double)result.Pop();
                                oper1 = (double)result.Pop();
                                if (oper1 != oper2) tmp = 1;
                                else tmp = 0;
                                result.Push(tmp);
                            }
                            else throw new CSException("Evaluation error at: !=");
                            break;
                        }
                    case TokenType.CAND:
                        {
                            if (result.Count >= 2)
                            {
                                oper2 = (double)result.Pop();
                                oper1 = (double)result.Pop();
                                if ((oper1 > 0) && (oper2 > 0)) tmp = 1;
                                else tmp = 0;
                                result.Push(tmp);
                            }
                            else throw new CSException("Evaluation error at: and");
                            break;
                        }
                    case TokenType.COR:
                        {
                            if (result.Count >= 2)
                            {
                                oper2 = (double)result.Pop();
                                oper1 = (double)result.Pop();
                                if ((oper1 > 0) || (oper2 > 0)) tmp = 1;
                                else tmp = 0;
                                result.Push(tmp);
                            }
                            else throw new CSException("Evaluation error at: or");
                            break;
                        }
                    case TokenType.Or:
                        {
                            if (result.Count >= 2)
                            {
                                oper2 = (double)result.Pop();
                                oper1 = (double)result.Pop();
                                tmp = Convert.ToDouble(Convert.ToInt32(oper1) | Convert.ToInt32(oper2));
                                result.Push(tmp);
                            }
                            else throw new CSException("Evaluation error at: |");
                            break;
                        }
                    case TokenType.And:
                        {
                            if (result.Count >= 2)
                            {
                                oper2 = (double)result.Pop();
                                oper1 = (double)result.Pop();
                                tmp = Convert.ToDouble(Convert.ToInt32(oper1) & Convert.ToInt32(oper2));
                                result.Push(tmp);
                            }
                            else throw new CSException("Evaluation error at: &");
                            break;
                        }
                    case TokenType.Biggerthan:
                        {
                            if (result.Count >= 2)
                            {
                                oper2 = (double)result.Pop();
                                oper1 = (double)result.Pop();
                                if (oper1 > oper2) tmp = 1;
                                else tmp = 0;
                                result.Push(tmp);
                            }
                            else throw new CSException("Evaluation error at: >");
                            break;
                        }
                    case TokenType.Multiply:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            result.Push(oper1 * oper2);
                        }
                        else throw new CSException("Evaluation error at: *");
                        break;
                    case TokenType.Divide:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            result.Push(oper1 / oper2);
                        }
                        else throw new CSException("Evaluation error at: /");
                        break;
                    case TokenType.Mod:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            result.Push(MathFuncts.mod(oper1, oper2));
                        }
                        else throw new CSException("Evaluation error at: %");
                        break;
                    case TokenType.Exponent:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            result.Push(Math.Pow(oper1, oper2));
                        }
                        else throw new CSException("Evaluation error at: ^");
                        break;
                    case TokenType.UnaryMinus:
                        if (result.Count >= 1)
                        {
                            oper1 = (double)result.Pop();
                            result.Push(-oper1);
                        }
                        else throw new CSException("Evaluation error at: -(unary)");
                        break;
                    case TokenType.OpStore:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            Program.loaded.Mem[lastvar] = oper2;
                            result.Push(oper2);
                        }
                        else throw new CSException("Evaluation error at: :=");
                        break;
                    case TokenType.OpStoreAdd:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            Program.loaded.Mem[lastvar] += oper2;
                            result.Push(oper2);
                        }
                        else throw new CSException("Evaluation error at: :=");
                        break;
                    case TokenType.OpStoreSub:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            Program.loaded.Mem[lastvar] -= oper2;
                            result.Push(oper2);
                        }
                        else throw new CSException("Evaluation error at: :=");
                        break;
                    case TokenType.OpStoreMul:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            Program.loaded.Mem[lastvar] *= oper2;
                            result.Push(oper2);
                        }
                        else throw new CSException("Evaluation error at: :=");
                        break;
                    case TokenType.OpStoreDiv:
                        if (result.Count >= 2)
                        {
                            oper2 = (double)result.Pop();
                            oper1 = (double)result.Pop();
                            Program.loaded.Mem[lastvar] /= oper2;
                            result.Push(oper2);
                        }
                        else throw new CSException("Evaluation error at: :=");
                        break;
                    case TokenType.FuncToken:
                        reqparams = ReversePolishNotation.Functions[token.TokenValue];
                        if (result.Count >= reqparams)
                        {
                            object[] param = new object[reqparams];
                            for (int i = 0; i < reqparams; i++) param[i] = (double)result.Pop();
                            Array.Reverse(param);
                            result.Push(ReversePolishNotation.Functions.InvokeFunction(token.TokenValue, param));
                        }
                        else throw new CSException("Evaluation error at function: " + token.TokenValue);
                        break;
                    case TokenType.UserFunction:
                        reqparams = Program.functionmem[token.TokenValue.ToUpper()].reqparams;
                        if (result.Count >= reqparams)
                        {
                            double[] param = new double[reqparams];
                            for (int i = 0; i < reqparams; i++) param[i] = (double)result.Pop();
                            Array.Reverse(param);
                            result.Push(FunctionLoader.CallUserFunction(token.TokenValue, param));
                        }
                        break;
                    case TokenType.ParamSeperator:
                        break;
                }
            }

            // If there is only one value in the stack
            if (result.Count == 1)
            {
                // That value is the result of the calculation.
                return (double)result.Pop();
            }
            else
            {
                // If there are more values in the stack
                // (Error) The user input too many values.
                throw new CSException("Evaluation error: "+this.PostfixExpression);
            }
        }

        public static bool IsOperatorToken(TokenType t)
        {
            switch (t)
            {
                case TokenType.Plus:
                case TokenType.Minus:
                case TokenType.Multiply:
                case TokenType.Divide:
                case TokenType.Exponent:
                case TokenType.UnaryMinus:
                case TokenType.Biggerthan:
                case TokenType.Smallerthan:
                case TokenType.And:
                case TokenType.Or:
                case TokenType.COR:
                case TokenType.CAND:
                case TokenType.CEQ:
                case TokenType.CNEQ:
                case TokenType.Mod:
                    return true;
                default:
                    return false;
            }
        }
    }
}